package com.cryptoneedle.center.source.entity.metadata;


import com.bubbles.engine.data.core.entity.BaseEntity;
import com.cryptoneedle.center.source.enums.DatabaseType;
import com.cryptoneedle.center.source.key.metadata.SourceServerKey;
import jakarta.persistence.*;
import lombok.*;
import lombok.experimental.Accessors;
import org.hibernate.annotations.Comment;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>description: 源数据源-目录 </p>
 *
 * @author CryptoNeedle
 * @date 2025-06-19
 */
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true, exclude = {"sourceJdbc", "sourceDatabases"})
@ToString(callSuper = true, exclude = {"sourceJdbc", "sourceDatabases"})
@Entity
@EntityListeners(AuditingEntityListener.class)
@Table(schema = "public", name = "source_catalog", uniqueConstraints = @UniqueConstraint(name = "uk_source_catalog_source_system_code", columnNames = {"transformSystemCode"}))
@Comment("源数据源-目录")
public class SourceCatalog extends BaseEntity {
    
    @Id
    @Comment("源数据源-目录名称")
    private String sourceCatalogName;
    
    @Comment("源数据源-系统编码")
    private String sourceSystemCode;
    
    @Comment("源数据源-启用目录")
    private Boolean sourceCatalogEnabled;
    
    @Embedded
    private Server server;
    
    @Embedded
    private Jdbc jdbc;

    @Comment("源数据源-SSH主机")
    private String sshHost;
    
    @Embedded
    private Transform transform;
    
    @Embedded
    private Doris doris;
    
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @Embeddable
    public static class Server {
        
        @Comment("服务器-主机")
        private String host;
        
        @Comment("服务器-端口")
        private Integer port;
        
        public SourceServerKey getKey() {
            return new SourceServerKey().setHost(this.host)
                                        .setPort(this.port);
        }
        
        public String getInetAddress() {
            return this.host + ":" + this.port;
        }
    }
    
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @Embeddable
    public static class Jdbc {
        
        @Enumerated(EnumType.STRING)
        @Comment("元数据-数据库类型")
        private DatabaseType databaseType;
        
        @Comment("JDBC-路径")
        private String route;
        
        @Comment("元数据-用户名称")
        private String userName;
    }
    
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @Embeddable
    public static class Transform {
        
        @Comment("转换-系统编码")
        private String transformSystemCode;
    }
    
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @Embeddable
    public static class Doris {
        
        @Comment("DORIS-可连接")
        private Boolean dorisConnected;
        
        @Comment("DORIS-最后可连接时间")
        private Date dorisConnectedDatetime;
    }
    
    /**
     * 关联关系
     */
    
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumns({@JoinColumn(name = "host", referencedColumnName = "host", insertable = false, updatable = false), @JoinColumn(name = "port", referencedColumnName = "port", insertable = false, updatable = false), @JoinColumn(name = "databaseType", referencedColumnName = "databaseType", insertable = false, updatable = false), @JoinColumn(name = "route", referencedColumnName = "route", insertable = false, updatable = false), @JoinColumn(name = "userName", referencedColumnName = "userName", insertable = false, updatable = false)})
    private SourceJdbc sourceJdbc;
    
    @OneToMany(mappedBy = "sourceCatalog", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceDatabase> sourceDatabases = new ArrayList<>();
    
    public SourceCatalog addSourceDatabase(SourceDatabase sourceDatabase) {
        this.sourceDatabases.add(sourceDatabase);
        sourceDatabase.setSourceCatalog(this);
        sourceDatabase.setSourceCatalogName(this.sourceCatalogName);
        return this;
    }
    
    public SourceCatalog removeSourceDatabase(SourceDatabase sourceDatabase) {
        // 从父实体的集合中移除子实体
        this.sourceDatabases.remove(sourceDatabase);
        // 清除子实体对父实体的引用
        sourceDatabase.setSourceCatalog(null);
        return this;
        
        // 关于 sourceDatabase.setSourceCatalog(null) 的写法说明:
        // 1.可清除双向的引用关系
        // 2.配合 orphanRemoval = true 实现 sourceDatabase 的删除
        // 3.确保一致性
        //   示例:
        //   catalog.addSourceDatabase();
        //   database.getSourceCatalog() == catalog; // true
        //
        //   catalog.removeSourceDatabase();
        //   database.getSourceCatalog() == null; // 如果不写 -> false 出现逻辑错误
        //   !catalog.getSourceDatabases().contains(database); // true
        // 4.防止内存泄露
        //   示例:
        //   SourceDatabase database = catalog.getSourceDatabases().get(0);
        //   catalog.removeSourceDatabase(database);
        //   如果不写 -> 此时只从集合中移除,但 database.getSourceCatalog() 仍然指向 catalog
    }
    
    /**
     * 其他
     */
    
    public String getKey() {
        return sourceCatalogName;
    }
    
    public String getStringKey() {
        return getKey().toString();
    }
}
